package xqueue

import (
	"encoding/json"
	"errors"
	"time"
)

// 添加Queue队列
//
//	fun	队列下标
//	c	推入队列列表
func queue_add(fun string, c *FuncConf) {
	if c == nil || fun == "" {
		return
	}
	queue_list_lock.Lock()
	defer queue_list_lock.Unlock()
	if _, ok := queue_list[fun]; ok {
		return
	}
	queue_list[fun] = *c
}

// 移除队列任务
//
//	fun	队列下标
func queue_remove(fun string) {
	if fun == "" {
		return
	}
	queue_list_lock.Lock()
	defer queue_list_lock.Unlock()
	delete(queue_list, fun)
}

// 写入队列 直接写入二进制的方法，不会进行外层格式封装，一般用于外部程序通信使用
//
//	byt	待发送的消息内容
//	qe	运行该操作的驱动
func queue_set_byte(byt []byte, qe Queue) error {
	// 存在队列，直接调用队列推送
	err := qe.Set(byt)
	// 记录入队队列日志
	log("_._", false, byt, err)
	return err
}

// 写入延迟队列 直接写入二进制的方法，不会进行外层格式封装，一般用于外部程序通信使用
//
//	byt	待发送的消息内容
//	def	延迟时间
//	qe	运行该操作的驱动
func queue_set_def_byte(byt []byte, def time.Duration, qe Queue) error {
	// 存在队列，直接调用队列推送
	err := qe.SetDef(byt, def)
	// 记录入队队列日志
	log("_._."+def.String(), false, byt, err)
	return err
}

// 写入队列【若未开启队列的话，将不管队列方法执行的结果，即程序会运行0~1次，即使是失败，所以建议开启NSQ队列，用以保证任务能成功执行】
//
//	fun		写入的服务名称，对应读取时的名称配置
//	param	传入的参数，对应读取时的参数结构
//	qe		运行该操作的驱动
func queue_set(funs string, param any, qe Queue) error {
	if funs == "" {
		return errors.New("队列任务下标不允许为空")
	}
	if v, ok := queue_list[funs]; ok {
		// 记录入队队列日志
		log(funs, false, param, nil)
		// 不存在队列，直接使用go调用
		if qe == nil {
			params, _ := json.Marshal(param)
			go func() {
				err := v.Func(params)
				if err != nil {
					log(funs, true, param, err)
					return
				}
				log(funs, true, param, nil)
			}()
			return nil
		}
		// 存在队列，直接调用队列推送
		qe.Set([]byte(asJson(queue_struct{
			Func:     funs,              // 下标
			Param:    param,             // 请求参数
			SendTime: time.Now().Unix(), // 入队时间
			RunTime:  time.Now().Unix(), // 期望运行时间
		})))
		return nil
	} else if qe != nil {
		// 记录入队队列日志
		log(funs, false, param, nil)
		// 存在队列，直接调用队列推送
		return qe.Set([]byte(asJson(queue_struct{
			Func:     funs,              // 下标
			Param:    param,             // 请求参数
			SendTime: time.Now().Unix(), // 入队时间
			RunTime:  time.Now().Unix(), // 期望运行时间
		})))
	}
	// 记录队列写入日志
	log(funs, false, param, errors.New("队列任务不存在"))
	return errors.New("队列任务不存在")
}

// 写入队列-延迟执行
//
//	fun		写入的服务名称，对应读取时的名称配置
//	param	传入的参数，对应读取时的参数结构
//	def		延迟时间（如果传入的 qe 为 nil 的话，则采用 go 自带的 time.sleep 休眠来实现）
//	qe		执行该操作的驱动信息
func queue_set_def(funs string, param any, def time.Duration, qe Queue) error {
	if funs == "" {
		return errors.New("队列任务下标不允许为空")
	}
	if v, ok := queue_list[funs]; ok {
		// 记录入队队列日志
		log(funs, false, param, nil)
		// 不存在队列，直接使用go调用
		if qe == nil {
			go func() {
				time.Sleep(def)
				err := v.Func([]byte(asJson(param)))
				if err != nil {
					log(funs, true, param, err)
					return
				}
				log(funs, true, param, nil)
			}()
			return nil
		}
		// 存在队列，直接调用队列推送
		qe.SetDef([]byte(asJson(queue_struct{
			Func:     funs,                       // 下标
			Param:    param,                      // 请求参数
			SendTime: time.Now().Unix(),          // 入队时间
			RunTime:  time.Now().Add(def).Unix(), // 期望运行时间
		})), def)
		return nil
	} else if qe != nil {
		// 记录入队队列日志
		log(funs, false, param, nil)
		// 存在队列，直接调用队列推送
		return qe.SetDef([]byte(asJson(queue_struct{
			Func:     funs,                       // 下标
			Param:    param,                      // 请求参数
			SendTime: time.Now().Unix(),          // 入队时间
			RunTime:  time.Now().Add(def).Unix(), // 期望运行时间
		})), def)
	}
	// 记录队列写入日志
	log(funs, false, param, errors.New("队列任务不存在"))
	return errors.New("队列任务不存在")
}

// 将传入参数转换为json字符串
func asJson(param any) string {
	params, _ := json.Marshal(param)
	return string(params)
}

// 队列监听操作
// 队列最终的监听操作，此处通过执行 go Listen() 来进行队列的监听
// 若不需要监听，只需要推送的话，则不需要执行此函数
func queue_listen() {
	if _default == nil {
		return
	}
	_default.Listen(func(dat []byte) error {
		def := queue_struct{}
		err := json.Unmarshal(dat, &def)
		if err != nil {
			return err
		}
		if def.Func == "" {
			return errors.New("队列名称格式不符合规则")
		}
		// 正式开始处理
		if v, ok := queue_list[def.Func]; ok {
			// 存在该队列函数
			err = v.Func([]byte(asJson(def.Param)))
			log(def.Func, true, def.Param, err)
			return err
		}
		log(def.Func, true, def.Param, errors.New("队列监听不存在"))
		// 处理完成
		return nil
	})
}
